/**
 * 20220118：由原virtualPlane分离
 * 20220210:：修改片元着色器
 */
import {UniformsUtils, ShaderMaterial, UniformsLib, Vector2} from "three";

/**
 * 虚拟平面材质
 * @param values {object} 可选参数对象
 *      {
 *          center：vec2(0.5,0.5), {Vector2} 中心位置
 *          其它通用参数
 *      }
 */
export default class VirtualPlaneMaterial extends ShaderMaterial{
    constructor(values={}){
        super();
        this._init(values);
    }

    //......................................................public.....................................................

    get center(){
        return this.uniforms.center.value;
    }
    set center(vec2){
        this.uniforms.center.value.copy(vec2);
    }
    get diffuse(){
        return this.uniforms.diffuse.value;
    }
    set diffuse(col){
        this.uniforms.diffuse.value.copy(col);
    }
    get map(){
        return this.uniforms.map.value;
    }
    set map(map){
        this.defines['USE_MAP']=map?'':undefined;
        this.uniforms.map.value=map;
    }
    get alphaMap(){
        return this.uniforms.alphaMap.value;
    }
    set alphaMap(map){
        this.defines['USE_ALPHAMAP']=map?'':undefined;
        this.uniforms.alphaMap.value=map;
    }
    get alphaTest(){
        return this.uniforms.alphaTest.value;
    }
    set alphaTest(num){
        this.defines['USE_ALPHATEST']=num?'':undefined;
        this.uniforms.alphaTest.value=num;
    }

    //.....................................................private.....................................................

    _init(values){
        this._initVertexShader();
        this._initFragmentShader();
        this._initUniforms(values);
        this._initOriParas(values);
    }
    _initUniforms(values){
        this.type='VirtualPlaneMaterial';
        this.uniforms=UniformsUtils.merge([
            UniformsLib.common,
            {
                center:{value:values.center||new Vector2(0.5,0.5)},
            }
        ]);
    }
    _initVertexShader(){
        this.vertexShader=`
            #include <common>
            #include <uv_pars_vertex>
            #include <color_pars_vertex>
            #include <fog_pars_vertex>
            #include <logdepthbuf_pars_vertex>
            attribute vec2 direction;
            uniform vec2 center;
            void main() {
                #include <uv_vertex>
                #include <color_vertex>
                #include <begin_vertex>
                #include <project_vertex>
                #include <logdepthbuf_vertex>
                #include <worldpos_vertex>
                #include <fog_vertex>
                
                vec3 dv=vec3(direction,0.);
                dv.x+=abs(dv.x)*(center.x-0.5);
                dv.y+=abs(dv.y)*(center.y-0.5);
                dv*=0.5;
                #ifdef USE_INSTANCING
                    mat3 m = mat3( instanceMatrix );
                    dv=m*dv;
                #else
                    mat3 m= mat3(modelMatrix);
                    dv=m*dv;
                #endif
                mvPosition.xyz+=dv;
                vec4 pmv=projectionMatrix*mvPosition;
                gl_Position=pmv;
            }
        `;
    }
    _initFragmentShader(){
        this.fragmentShader=`
            uniform vec3 diffuse;
            uniform float opacity;
            #include <common>
            #include <color_pars_fragment>
            #include <uv_pars_fragment>
            #include <map_pars_fragment>
            #include <alphamap_pars_fragment>
            #include <alphatest_pars_fragment>
            #include <fog_pars_fragment>
            #include <logdepthbuf_pars_fragment>
            void main() {
                vec4 diffuseColor = vec4( diffuse, opacity );
                #include <logdepthbuf_fragment>
                #include <map_fragment>
                #include <color_fragment>
                #include <alphamap_fragment>
                #include <alphatest_fragment>
                ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
                reflectedLight.indirectDiffuse += vec3( 1.0 );
                reflectedLight.indirectDiffuse *= diffuseColor.rgb;
                vec3 outgoingLight = reflectedLight.indirectDiffuse;
                #include <output_fragment>
                #include <tonemapping_fragment>
                #include <encodings_fragment>
                #include <fog_fragment>
                #include <premultiplied_alpha_fragment>
            }
        `;
    }
    _getExclusiveKeys(){
        return ['center'];
    }
    _initOriParas(values){
        let ecl=this._getExclusiveKeys();
        for(let k in values){
            let key=k+'';
            if(ecl.includes(key))continue;
            this[key]=values[key];
        }
        this.needsUpdate=true;
    }
}